package cl.gob.ips.offline.jbpm;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.ejb.Stateless;

import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.context.exe.ContextInstance;
import org.jbpm.db.GraphSession;
import org.jbpm.db.TaskMgmtSession;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.taskmgmt.exe.TaskInstance;

import cl.gob.ips.offline.util.DatosProceso;
import cl.gob.ips.offline.util.ParseaTareas;

/**
 * Session Bean implementation class JBPMBean
 */
@Stateless
public class JBPMBean implements JBPMBeanRemote {

	public void finalizarProcesoActivo(String key, String transicion) {
		System.out.println("Signal");
		JbpmConfiguration conf = JbpmConfiguration.getInstance();
		JbpmContext ctx = conf.createJbpmContext();
		try {
			GraphSession gs = ctx.getGraphSession();

			// se busca la ultima version de la defincion de proceso 'process'
			ProcessDefinition pd = gs.findLatestProcessDefinition("procesoIPS");

			// se obtienen todas las instancias de procesos asociadas a la
			// definicion de proceso
			List<ProcessInstance> listPI = gs.findProcessInstances(pd.getId());

			// se itera sobre la lista de instancias
			long instanciaId = 0;
			for (int i = 0; i < listPI.size(); i++) {
				if (listPI.get(i).getKey().equals(key)) {
					System.out.println("Haciendo signal a la instancia :"
							+ listPI.get(i).getId());
					listPI.get(i).signal(transicion);
					break;
				}
			}
		} catch (Exception e) {
			System.out.println(e);
		} finally {
			try {
				ctx.close();
				conf.close();
			} catch (Exception e) {
				System.out.println(e);
			}
		}
	}

	public void cierraTarea(int taskId, String tarea) {
		System.out.println("Finalizando Tarea");

		JbpmConfiguration conf = JbpmConfiguration.getInstance();
		JbpmContext ctx = conf.createJbpmContext();

		try {
			GraphSession gs = ctx.getGraphSession();

			// se busca la ultima version de la defincion de proceso 'process'
			ProcessDefinition pd = gs.findLatestProcessDefinition("procesoIPS");

			// se obtienen todas las instancias de procesos asociadas a la
			// definicion de proceso
			List<ProcessInstance> listPI = gs.findProcessInstances(pd.getId());

			TaskMgmtSession taskMgmtSession = ctx.getTaskMgmtSession();
			taskMgmtSession.loadTaskInstance((long) taskId);
			TaskInstance taskInstance = taskMgmtSession.getTaskInstance((long) taskId);
			
			if(tarea != null){
				taskInstance.end(tarea);
			}else{
				taskInstance.end();
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

		finally {
			try {
				ctx.close();
				conf.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public DatosProceso obtieneDatosProceso(int taskId) {//TODO
		System.out.println("Finalizando Tarea");

		JbpmConfiguration conf = JbpmConfiguration.getInstance();
		JbpmContext ctx = conf.createJbpmContext();
		DatosProceso datosProceso = new DatosProceso();

		try {
			GraphSession gs = ctx.getGraphSession();

			// se busca la ultima version de la defincion de proceso 'process'
			ProcessDefinition pd = gs.findLatestProcessDefinition("procesoIPS");

			// se obtienen todas las instancias de procesos asociadas a la
			// definicion de proceso
			List<ProcessInstance> listPI = gs.findProcessInstances(pd.getId());
			ProcessInstance processInstance = listPI.get(0);
			ContextInstance contextInstance = processInstance
					.getContextInstance();
			datosProceso.setNombre(contextInstance.getVariable("nombre")
					.toString());
			datosProceso.setRut(contextInstance.getVariable("rut").toString());
			datosProceso
					.setArea(contextInstance.getVariable("area").toString());
			datosProceso.setKey(processInstance.getKey());
			/*
			 * TaskMgmtSession taskMgmtSession = ctx.getTaskMgmtSession();
			 * TaskInstance taskInstance =
			 * taskMgmtSession.getTaskInstance(taskId);
			 * taskInstance.end("calculo");
			 */

		} catch (Exception e) {
			System.out.println(e);
		}

		finally {
			try {
				ctx.close();
				conf.close();
			} catch (Exception e) {
				System.out.println(e);
			}
		}
		return datosProceso;
	}

	public void seteaVariablesTarea(String key, String nombreTarea,
			String variable, String valor) {
		System.out.println("Signal");
		JbpmConfiguration conf = JbpmConfiguration.getInstance();

		JbpmContext ctx = conf.createJbpmContext();

		try {
			GraphSession gs = ctx.getGraphSession();

			// se busca la ultima version de la defincion de proceso 'process'
			ProcessDefinition pd = gs.findLatestProcessDefinition("procesoIPS");

			// se obtienen todas las instancias de procesos asociadas a la
			// definicion de proceso
			List<ProcessInstance> listPI = gs.findProcessInstances(pd.getId());

			// se itera sobre la lista de instancias
			long instanciaId = 0;
			for (int i = 0; i < listPI.size(); i++) {
				if (listPI.get(i).getKey().equals(key)) {
					TaskMgmtSession taskMgmtSession = ctx.getTaskMgmtSession();
					List process = taskMgmtSession
							.findTaskInstancesByProcessInstance(listPI.get(i));
					for (int j = 0; j < process.size(); j++) {
						TaskInstance ti = (TaskInstance) process.get(j);
						if (ti.getName().equals(nombreTarea)) {
							ti.setVariable(variable, valor);
							break;
						}
					}
					listPI.get(i).getContextInstance()
							.setVariable(variable, valor);
					break;
				}

			}

		} catch (Exception e) {
			System.out.println(e);
		}

		finally {
			try {
				ctx.close();
				conf.close();
			} catch (Exception e) {
				System.out.println(e);
			}
		}
	}

	public List getAssignedTasks(String rol, String tipo) {
		System.out.println("API");
		JbpmConfiguration conf = JbpmConfiguration.getInstance();

		JbpmContext ctx = conf.createJbpmContext();
		List listaTareas = new ArrayList();
		List tareasTipo = new ArrayList();
		try {

			TaskMgmtSession taskMgmtSession = ctx.getTaskMgmtSession();
			listaTareas = taskMgmtSession.findPooledTaskInstances(rol);

			for (int i = 0; i < listaTareas.size(); i++) {
				TaskInstance ti = (TaskInstance) listaTareas.get(i);
				if (ti.getVariable("tipo").equals(tipo)) {
					tareasTipo.add(ti);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			ctx.close();
			conf.close();
		}
		if (tareasTipo.isEmpty()) {
			TaskInstance ss = new TaskInstance();
			ss.setName("");
			ss.setDescription("No existen tareas asociadas al rol " + rol + " "
					+ tipo);
			tareasTipo.add(ss);
		}
		return ParseaTareas.parseaSalidaListaTareas(tareasTipo);
	}
	
	/**
	 * @param key
	 * @param nombreProceso
	 * @return
	 */
	public long getTaskID(String key, String nombreProceso){
		long taskId = 0;
		JbpmConfiguration conf	= JbpmConfiguration.getInstance();
		JbpmContext ctx			= conf.createJbpmContext();
		
		try{
			GraphSession gs		= ctx.getGraphSession();
			ProcessDefinition pd= gs.findLatestProcessDefinition(nombreProceso);
			@SuppressWarnings("unchecked")
			List<ProcessInstance> listPI = gs.findProcessInstances(pd.getId());
			
			for(ProcessInstance process : listPI){
				if(process.getKey() != null && process.getKey().equals(key)){
					taskId = process.getId();
					break;
				}
			}		
			
		}catch (Exception e) {
			e.printStackTrace();
		}finally{
			this.closeContext(ctx);
		}
		
		return taskId;
	}
	
	/**
	 * @param ctx
	 */
	private void closeContext(JbpmContext ctx){
		if (ctx != null){
			ctx.close();
		}
	}

	public void inicializaProceso(String nombreProceso, String key,
			String NombreFuncionarioCap) {
		// se debe obtener el contexto JBPM, con los archivos cfg de jbpm e
		// hibernate
		Logger log = Logger.getLogger(JBPMBean.class.getName());
		log.log(Level.INFO, "Obteniendo Contexto JBPM ...");
		JbpmConfiguration conf = JbpmConfiguration.getInstance();
		JbpmContext ctx = conf.createJbpmContext();

		try {

			// se debe instanciar procesos segun el nombre de la definicion de
			// proceso jbpm (JPDL)
			String processDefinitionName = "nameDefinitionProcess";
			log.log(Level.INFO, "Instanciando  definicion de proceso "
					+ nombreProceso);
			ProcessInstance processInstance = ctx
					.newProcessInstanceForUpdate(nombreProceso);
			processInstance.setKey(key);
			log.log(Level.INFO, "Seteando variables ...");
			// setear variablas al contexto de la instancia de proceso
			ContextInstance contextInstance = processInstance
					.getContextInstance();
			contextInstance.setVariable("NombreFuncionarioCap",
					NombreFuncionarioCap);

			// se da un signal para que quede en el siguiente nodo de espera. en
			// el caso que no se necesita mover el token comentar el signal
			processInstance.signal();

			// se persiste el contexto
			ctx.save(processInstance);

			// se obtiene el id del proceso
			log.log(Level.INFO, "Obteniendo y seteando  Id de tramite -> "
					+ processInstance.getId());

		} catch (Exception e) {
			log.log(Level.SEVERE, e.getMessage(), e);
		} finally {
			// se cierra y se libera el contexto
			log.log(Level.INFO, "Cerrando contexto Jbpm ...");
			if (ctx != null)
				ctx.close();
		}

	}
}
